#include "core/LoggerService.h"
#include <iostream>
#include <fstream>
#include <ctime>
#include <iomanip>
#include <mutex>

namespace core {

LoggerService::LoggerService(const std::string& name) 
    : name_(name), logLevel_(LogLevel::INFO), dateFormat_("%Y-%m-%d %H:%M:%S"),
      logFormat_("[%d] [%l] [%n] %m"), fileOutputEnabled_(false), 
      consoleOutputEnabled_(true) {}

LoggerService::~LoggerService() {
    if (logFile_.is_open()) {
        logFile_.close();
    }
}

bool LoggerService::initialize() {
    return true;
}

bool LoggerService::initialize(const std::string& logFilePath) {
    logFile_.open(logFilePath, std::ios::app);
    fileOutputEnabled_ = logFile_.is_open();
    return fileOutputEnabled_;
}

std::string LoggerService::getName() const {
    return name_;
}

void LoggerService::setLogLevel(LogLevel level) {
    std::lock_guard<std::mutex> lock(logMutex_);
    logLevel_ = level;
}

LogLevel LoggerService::getLogLevel() const {
    return logLevel_;
}

void LoggerService::trace(const std::string& message) {
    log(LogLevel::TRACE, message);
}

void LoggerService::debug(const std::string& message) {
    log(LogLevel::DEBUG, message);
}

void LoggerService::info(const std::string& message) {
    log(LogLevel::INFO, message);
}

void LoggerService::warning(const std::string& message) {
    log(LogLevel::WARNING, message);
}

void LoggerService::error(const std::string& message) {
    log(LogLevel::ERROR, message);
}

void LoggerService::fatal(const std::string& message) {
    log(LogLevel::FATAL, message);
}

void LoggerService::tracef(const char* format, ...) {
    va_list args;
    va_start(args, format);
    logFormatted(LogLevel::TRACE, format, args);
    va_end(args);
}

void LoggerService::debugf(const char* format, ...) {
    va_list args;
    va_start(args, format);
    logFormatted(LogLevel::DEBUG, format, args);
    va_end(args);
}

void LoggerService::infof(const char* format, ...) {
    va_list args;
    va_start(args, format);
    logFormatted(LogLevel::INFO, format, args);
    va_end(args);
}

void LoggerService::warningf(const char* format, ...) {
    va_list args;
    va_start(args, format);
    logFormatted(LogLevel::WARNING, format, args);
    va_end(args);
}

void LoggerService::errorf(const char* format, ...) {
    va_list args;
    va_start(args, format);
    logFormatted(LogLevel::ERROR, format, args);
    va_end(args);
}

void LoggerService::fatalf(const char* format, ...) {
    va_list args;
    va_start(args, format);
    logFormatted(LogLevel::FATAL, format, args);
    va_end(args);
}

void LoggerService::logFormatted(LogLevel level, const char* format, va_list args) {
    if (level < logLevel_) {
        return;
    }

    char buffer[1024];
    vsnprintf(buffer, sizeof(buffer), format, args);
    log(level, std::string(buffer));
}

void LoggerService::setFileOutputEnabled(bool enabled) {
    std::lock_guard<std::mutex> lock(logMutex_);
    fileOutputEnabled_ = enabled;
}

void LoggerService::setConsoleOutputEnabled(bool enabled) {
    std::lock_guard<std::mutex> lock(logMutex_);
    consoleOutputEnabled_ = enabled;
}

void LoggerService::setDateFormat(const std::string& format) {
    std::lock_guard<std::mutex> lock(logMutex_);
    dateFormat_ = format;
}

void LoggerService::setLogFormat(const std::string& format) {
    std::lock_guard<std::mutex> lock(logMutex_);
    logFormat_ = format;
}

void LoggerService::log(LogLevel level, const std::string& message) {
    if (level < logLevel_) {
        return;
    }

    std::lock_guard<std::mutex> lock(logMutex_);
    
    auto now = std::time(nullptr);
    auto tm = *std::localtime(&now);
    char timeStr[80];
    std::strftime(timeStr, sizeof(timeStr), dateFormat_.c_str(), &tm);
    
    std::string logEntry = logFormat_;
    std::string levelStr = levelToString(level);
    
    // Replace placeholders
    size_t pos;
    while ((pos = logEntry.find("%d")) != std::string::npos) {
        logEntry.replace(pos, 2, timeStr);
    }
    while ((pos = logEntry.find("%l")) != std::string::npos) {
        logEntry.replace(pos, 2, levelStr);
    }
    while ((pos = logEntry.find("%n")) != std::string::npos) {
        logEntry.replace(pos, 2, name_);
    }
    while ((pos = logEntry.find("%m")) != std::string::npos) {
        logEntry.replace(pos, 2, message);
    }

    if (consoleOutputEnabled_) {
        std::cout << logEntry << std::endl;
    }

    if (fileOutputEnabled_ && logFile_.is_open()) {
        logFile_ << logEntry << std::endl;
    }
}

std::string LoggerService::levelToString(LogLevel level) const {
    switch (level) {
        case LogLevel::TRACE: return "TRACE";
        case LogLevel::DEBUG: return "DEBUG";
        case LogLevel::INFO: return "INFO";
        case LogLevel::WARNING: return "WARNING";
        case LogLevel::ERROR: return "ERROR";
        case LogLevel::FATAL: return "FATAL";
        default: return "UNKNOWN";
    }
}

} // namespace core